#ifndef DSO_RESIDUALS_H
#define DSO_RESIDUALS_H

#include <vector>
#include <fstream>

#include "dso/util/GlobalFuncs.h"
#include "dso/util/GlobalCalib.h"
#include "dso/OptimizationBackend/RawResidualJacobian.h"

namespace dso 
{
    
// forward declare 
class PointHessian;
class FrameHessian;
class CalibHessian;
class EFResidual;


enum ResLocation {ACTIVE=0, LINEARIZED, MARGINALIZED, NONE};
enum ResState {IN=0, OOB, OUTLIER}; // Residual state: inside, outside, outlier

// ???
struct FullJacRowT
{
    Eigen::Vector2f projectedTo[MAX_RES_PER_POINT];
};

// Reprojection Error 
class PointFrameResidual
{
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    PointFrameResidual();
    PointFrameResidual(PointHessian* point_, FrameHessian* host_, FrameHessian* target_);
    ~PointFrameResidual();
    
    // linearize the reprojection
    double linearize(CalibHessian* HCalib);
    
    void resetOOB()
    {
        state_NewEnergy = state_energy = 0;
        state_NewState = ResState::OUTLIER;
        setState(ResState::IN);
    };
    
    // 将state_NewState的状态更新至当前状态 
    void applyRes( bool copyJacobians);

    void debugPlot();

    void setState(ResState s) {state_state = s;}
    
    EFResidual* efResidual;

    static int instanceCounter;
    ResState state_state;
    double state_energy=0;
    ResState state_NewState;
    double state_NewEnergy=0;
    double state_NewEnergyWithOutlier=0;
    
    PointHessian* point =nullptr;
    FrameHessian* host =nullptr;
    FrameHessian* target =nullptr;
    RawResidualJacobian* J =nullptr;
    
    bool isNew =true;
    Eigen::Vector2f projectedTo[MAX_RES_PER_POINT]; // 从host到target的投影点
    Vec3f centerProjectedTo;

};
    
    
}

#endif